home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / thomas / thomas.lha / Thomas / Thomas-1.1 / src / class.scm < prev    next >
Text File  |  1992-09-21  |  31KB  |  851 lines

  1. ;*              Copyright 1992 Digital Equipment Corporation
  2. ;*                         All Rights Reserved
  3. ;*
  4. ;* Permission to use, copy, and modify this software and its documentation is
  5. ;* hereby granted only under the following terms and conditions.  Both the
  6. ;* above copyright notice and this permission notice must appear in all copies
  7. ;* of the software, derivative works or modified versions, and any portions
  8. ;* thereof, and both notices must appear in supporting documentation.
  9. ;*
  10. ;* Users of this software agree to the terms and conditions set forth herein,
  11. ;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
  12. ;* right and license under any changes, enhancements or extensions made to the
  13. ;* core functions of the software, including but not limited to those affording
  14. ;* compatibility with other hardware or software environments, but excluding
  15. ;* applications which incorporate this software.  Users further agree to use
  16. ;* their best efforts to return to Digital any such changes, enhancements or
  17. ;* extensions that they make and inform Digital of noteworthy uses of this
  18. ;* software.  Correspondence should be provided to Digital at:
  19. ;*
  20. ;*            Director, Cambridge Research Lab
  21. ;*            Digital Equipment Corp
  22. ;*            One Kendall Square, Bldg 700
  23. ;*            Cambridge MA 02139
  24. ;*
  25. ;* This software may be distributed (but not offered for sale or transferred
  26. ;* for compensation) to third parties, provided such third parties agree to
  27. ;* abide by the terms and conditions of this notice.
  28. ;*
  29. ;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  30. ;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  31. ;* MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  32. ;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  33. ;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  34. ;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  35. ;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  36. ;* SOFTWARE.
  37.  
  38. ; $Id: class.scm,v 1.24 1992/09/21 20:41:56 birkholz Exp $
  39.  
  40. ;;;; Class, Instance, and Singleton data types.
  41.  
  42. ;;; Conventions:
  43. ;;;
  44. ;;; "dylan:" is a prefix used for variables used in the expanded code
  45. ;;;          generated by our dylan->scheme compiler.  All such
  46. ;;;          functions are expecting to be called using Dylan calling
  47. ;;;          syntax (i.e. they send both a multiple-value and a next-method
  48. ;;;          argument).  These are typically called from Scheme using the
  49. ;;;          dylan-call procedure which defaults the special arguments.
  50. ;;;
  51. ;;; "dylan::" is a prefix for functions used by the Runtime library, but
  52. ;;;           not directly available from Dylan.  These use the normal
  53. ;;;           scheme calling convensions.
  54. ;;;
  55. ;;; Capitalization (per word) is used for Dylan variables defined in
  56. ;;; Scheme.
  57.  
  58. ;;; Things visible to converted Dylan code.  Just the names here...
  59.  
  60. (define dylan::make-a-class '...)
  61. (define Add-Slot '...)
  62. (define Id? eq?)
  63. (define dylan::add-slot '...)
  64. (define dylan::false-fn (lambda () #F))
  65. (define Subclass? '...)
  66. (define map-over-all-superclasses! '...)
  67. (define map-over-all-subclasses! '...)
  68.  
  69. ; (let ()
  70. ;;; Scheme structure for representing the Dylan class DAG
  71.  
  72. (define class-type
  73.   (make-record-type
  74.    'dylan-class
  75.    '(debug-name                ; Name, for debugging
  76.      instances                ; Population of all direct
  77.                     ; instances of this class
  78.      subclasses                ; Population of all direct
  79.                     ; subclasses of this class
  80.      superclasses            ; Ordered list of direct
  81.                     ; superclasses
  82.      slots                ; Vector of slot descriptors
  83.      class-data                ; Vector of data belonging to
  84.                     ; this class -- either from
  85.                     ; CLASS allocated data in one
  86.                     ; of my slots or from
  87.                     ; ALL-SUBCLASSES from
  88.                     ; inherited slots
  89.      instance-data-size            ; Number of slots in each INSTANCE
  90.      sealed?                ; Has the class been sealed?
  91.      read-only?
  92.      abstract?                ; Is the class abstract?
  93.      specificity            ; Longest path from root.
  94.      specificity-token            ; Unique to a specificity labeling.
  95.      )))
  96. (define class? (record-predicate class-type))
  97. (define make-class (record-constructor class-type))
  98. (define class.debug-name (record-accessor class-type 'debug-name))
  99. (define class.instances (record-accessor class-type 'instances))
  100. (define class.subclasses (record-accessor class-type 'subclasses))
  101. (define class.superclasses (record-accessor class-type 'superclasses))
  102. (define class.slots (record-accessor class-type 'slots))
  103. (define class.class-data (record-accessor class-type 'class-data))
  104. (define class.instance-data-size
  105.   (record-accessor class-type 'instance-data-size))
  106. (define class.sealed? (record-accessor class-type 'sealed?))
  107. (define class.read-only? (record-accessor class-type 'read-only?))
  108. (define class.abstract? (record-accessor class-type 'abstract?))
  109. (define class.specificity (record-accessor class-type 'specificity))
  110. (define class.specificity-token (record-accessor class-type 'specificity-token))
  111. (define set-class.instances!
  112.   (record-updater class-type 'instances))
  113. (define set-class.subclasses!
  114.   (record-updater class-type 'subclasses))
  115. (define set-class.superclasses!
  116.   (record-updater class-type 'superclasses))
  117. (define set-class.slots!
  118.   (record-updater class-type 'slots))
  119. (define set-class.class-data!
  120.   (record-updater class-type 'class-data))
  121. (define set-class.instance-data-size!
  122.   (record-updater class-type 'instance-data-size))
  123. (define set-class.sealed?!
  124.   (record-updater class-type 'sealed?))
  125. (define set-class.read-only?!
  126.   (record-updater class-type 'read-only?))
  127. (define set-class.abstract?!
  128.   (record-updater class-type 'abstract?))
  129. (define set-class.specificity! (record-updater class-type 'specificity))
  130. (define set-class.specificity-token!
  131.   (record-updater class-type 'specificity-token))
  132.  
  133. ;;; Scheme structure for representing Dylan singletons
  134.  
  135. (define singleton-type
  136.   (make-record-type
  137.    'dylan-singleton
  138.    '(object                ; The actual singleton object
  139.      extra-slot-descriptors        ; Vector of slot descriptors
  140.                     ; for slots only in singleton
  141.                     ; and not in class definition
  142.      extra-slot-values)))        ; Vector of extra slot data
  143.  
  144. (define singleton? (record-predicate singleton-type))
  145. (define make-singleton (record-constructor singleton-type))
  146. (define singleton.object (record-accessor singleton-type 'object))
  147. (define singleton.extra-slot-descriptors
  148.   (record-accessor singleton-type 'extra-slot-descriptors))
  149. (define singleton.extra-slot-values
  150.   (record-accessor singleton-type 'extra-slot-values))
  151. (define set-singleton.extra-slot-descriptors!
  152.   (record-updater singleton-type 'extra-slot-descriptors))
  153. (define set-singleton.extra-slot-values!
  154.   (record-updater singleton-type 'extra-slot-values))
  155.  
  156. ;;; Scheme structure for representing Dylan slot descriptors
  157.  
  158. ;; moved to support.scm -- used by compiler and runtime
  159.  
  160. ;;; Scheme structure for representing Dylan instances
  161.  
  162. (define instance-type
  163.   (make-record-type
  164.    'dylan-instance
  165.    '(class                ; Direct class of this object
  166.      singleton                ; Singleton for this obj. (or #F)
  167.      data)))                ; Vector of object's instance data
  168. (define instance? (record-predicate instance-type))
  169. (define make-instance (record-constructor instance-type))
  170. (define instance.class (record-accessor instance-type 'class))
  171. (define instance.singleton (record-accessor instance-type 'singleton))
  172. (define instance.data (record-accessor instance-type 'data))
  173. (define set-instance.class! (record-updater instance-type 'class))
  174. (define set-instance.singleton! (record-updater instance-type 'singleton))
  175. (define set-instance.data! (record-updater instance-type 'data))
  176.  
  177. ;;; And now the good stuff ...
  178.  
  179. (define (test-that-all-slots-for-this-getter-are-identical
  180.      my-slot my-getter slots)
  181.   (define (slots-equal? slot1 slot2)
  182.     (define (slot->list slot)
  183.       (map (lambda (f) (f slot))
  184.        (list slot.debug-name slot.getter slot.setter slot.type
  185.          slot.init-value slot.init-function slot.init-keyword
  186.          slot.required-init-keyword slot.allocation)))
  187.     (define (all? fn l1 l2)
  188.       (or (null? l1)
  189.       (and (fn (car l1) (car l2))
  190.            (all? fn (cdr l1) (cdr l2)))))
  191.     (all? eq? (slot->list slot1) (slot->list slot2)))
  192.   (let loop ((slots slots))
  193.     (cond ((null? slots) #T)
  194.       ((eq? (slot.getter (car slots)) my-getter)
  195.        (if (not (slots-equal? my-slot (car slots)))
  196.            (dylan-call dylan:error
  197.                "multiple inheritance slot clash"
  198.                my-slot (car slots))
  199.            (loop (cdr slots))))
  200.       (else (loop (cdr slots))))))
  201.  
  202. (define (vector-iterate v fn)
  203.   (do ((length (vector-length v))
  204.        (i 0 (+ i 1)))
  205.       ((= i length))
  206.     (fn i (vector-ref v i))))
  207.  
  208. (define (grow-vector v . values)
  209.   (let* ((values (list->vector values))
  210.      (n-old-values (vector-length v))
  211.      (new-v (make-vector (+ n-old-values
  212.                 (vector-length values)))))
  213.     (vector-iterate v
  214.       (lambda (i entry) (vector-set! new-v i entry)))
  215.     (vector-iterate values
  216.       (lambda (i entry)
  217.     (vector-set! new-v (+ i n-old-values) entry)))
  218.       new-v))
  219.  
  220. (define (find-empty-slot v)
  221.   (let ((length (vector-length v)))
  222.     (let loop ((i 0))
  223.       (cond ((= i length) #F)
  224.         ((not (vector-ref v i)) i)
  225.         (else (loop (+ i 1)))))))
  226.  
  227. (define (set-next-vector-entry! vec value update-vec!)
  228.   (let ((next-entry (find-empty-slot vec)))
  229.     (if next-entry
  230.     (vector-set! vec next-entry value)
  231.     (let ((new-vec (grow-vector vec #F #F #F #F #F #F #F #F #F #F)))
  232.       (update-vec! new-vec)
  233.       (set-next-vector-entry! new-vec value update-vec!)))))
  234.  
  235. (define (copy-slot slot inherited? data-location)
  236.   (apply make-slot
  237.      (map (lambda (fn) (fn slot))
  238.           (list slot.debug-name slot.getter slot.setter
  239.             slot.type slot.init-value
  240.             slot.has-initial-value? slot.init-function
  241.             slot.init-keyword slot.required-init-keyword
  242.             slot.allocation (lambda (s) s inherited?)
  243.             (lambda (s) s data-location)))))
  244.  
  245. (define (combine-slots class slots new-getter-fns)
  246.   (let ((class-data-index -1)
  247.     (instance-data-index -1))
  248.  
  249.     (define (figure-slot-data-location slot)
  250.       (case (slot.allocation slot)
  251.     ((CLASS CONSTANT) (slot.data-location slot))
  252.     ((INSTANCE)
  253.      (set! instance-data-index (+ 1 instance-data-index))
  254.      (if (not (= instance-data-index (slot.data-location slot)))
  255.          (begin
  256.            (add-method (slot.getter slot)
  257.                (make-instance-getter class
  258.                          instance-data-index
  259.                          (slot.debug-name slot)))
  260.            (if (slot.setter slot)
  261.            (add-method (slot.setter slot)
  262.                    (make-instance-setter
  263.                 class instance-data-index
  264.                 (slot.type slot))))))
  265.      instance-data-index)
  266.     ((EACH-SUBCLASS)
  267.      (set! class-data-index (+ 1 class-data-index))
  268.      (if (not (= class-data-index (slot.data-location slot)))
  269.          (begin
  270.            (add-method (slot.getter slot)
  271.                (make-each-subclass-getter class
  272.                               class-data-index
  273.                               (slot.debug-name slot)))
  274.            (if (slot.setter slot)
  275.            (add-method
  276.             (slot.setter slot)
  277.             (make-each-subclass-setter class class-data-index
  278.                            (slot.type slot))))))
  279.      class-data-index)
  280.     ((VIRTUAL) #F)))
  281.  
  282.     (define (combine-two-slotlists a b)
  283.       ;; NOTE: Question 8 resolved here by using EQ? on the
  284.       ;; superclass slot getter functions
  285.       (let loop ((slots a)
  286.          (getters (map slot.getter a))
  287.          (new-slots b))
  288.     (if (null? new-slots)
  289.         slots
  290.         (let* ((this-slot (car new-slots))
  291.            (this-getter (slot.getter this-slot)))
  292.           (if (memq this-getter getters) ; Slot already inherited?
  293.           (begin
  294.             (if (not (memq this-getter new-getter-fns))
  295.                     ; Not being overridden?
  296.             (test-that-all-slots-for-this-getter-are-identical
  297.              this-slot this-getter slots)) ; Must be identical
  298.             (loop slots getters (cdr new-slots)))
  299.           (loop (cons (copy-slot this-slot
  300.                      #T
  301.                      (figure-slot-data-location this-slot))
  302.                   slots)
  303.             (cons this-getter getters)
  304.             (cdr new-slots)))))))
  305.  
  306.     (define (reduce fn initial-value l)
  307.       (let loop ((value initial-value)
  308.          (l l))
  309.     (if (null? l)
  310.         value
  311.         (loop (fn value (car l)) (cdr l)))))
  312.  
  313.     (let ((final-slot-list (reverse (reduce combine-two-slotlists '() slots))))
  314.       (vector (list->vector final-slot-list)
  315.           (+ 1 class-data-index)
  316.           (+ 1 instance-data-index)))))
  317.  
  318. (define (recompute-class-specificities!)
  319.   (let ((new-token (cons 'SPECIFICITY 'TOKEN)))
  320.  
  321.     (define (level-me me level)
  322.       (if (eq? new-token (class.specificity-token me))
  323.       (if (> level (class.specificity me))
  324.           (set-class.specificity! me level))
  325.       (begin
  326.         (set-class.specificity-token! me new-token)
  327.         (set-class.specificity! me level)))
  328.       (let ((sublevel (+ 1 level)))
  329.     (map-over-population!
  330.      (class.subclasses me)
  331.      (lambda (subclass)
  332.        (level-me subclass sublevel)))))
  333.  
  334.     (level-me <object> 0)))
  335.  
  336. (define (get-initial-slot-value slot)
  337.   (cond ((slot.init-function slot) => (lambda (f) (dylan-call f)))
  338.     ((not (slot.has-initial-value? slot)) *the-uninitialized-slot-value*)
  339.     (else (slot.init-value slot))))
  340.  
  341. (define (initialize-slot! slot keywords vector which-allocation-types)
  342.   (let ((allocation (slot.allocation slot)))
  343.     (if (memq allocation which-allocation-types)
  344.     (case allocation
  345.       ((INSTANCE EACH-SUBCLASS)
  346.        (let ((keyword (or (slot.required-init-keyword slot)
  347.                   (slot.init-keyword slot))))
  348.          (vector-set! vector (slot.data-location slot)
  349.            (if keyword
  350.            (dylan::find-keyword keywords keyword
  351.              (lambda () (get-initial-slot-value slot)))
  352.            (get-initial-slot-value slot)))))
  353.       ((CLASS)
  354.        (vector-set! vector (cdr (slot.data-location slot))
  355.             (get-initial-slot-value slot)))
  356.       ((VIRTUAL CONSTANT) 'done))))
  357.   'DONE)
  358.  
  359. (set! dylan::make-a-class
  360.   (lambda (name superclasses new-getter-fns)
  361.     (make-dylan-class name superclasses new-getter-fns #F)))
  362.  
  363. (define (make-dylan-class name superclasses new-getter-fns top?)
  364.   (if (and (not top?)
  365.        (null? superclasses))
  366.       (dylan-call dylan:error "must specify at least one superclass"))
  367.   (if (not (unique? superclasses memq))
  368.       (dylan-call dylan:error
  369.           "multiple inheritance from identical superclasses"))
  370.   (let* ((the-class
  371.       (make-class
  372.        name                ; debug-name
  373.        (make-population)        ; instances
  374.        (make-population)        ; subclasses
  375.        superclasses            ; superclasses
  376.        '#()                ; slots
  377.        '#()                ; class-data
  378.        0                ; instance-data-size
  379.        #F                ; sealed?
  380.        #F                ; read-only?
  381.        #F                ; abstract?
  382.        #F                ; specificity
  383.        #F                ; specificity-token
  384.        ))
  385.      (combined-slots
  386.       (combine-slots
  387.        the-class
  388.        (map (lambda (class) (vector->list (class.slots class)))
  389.         superclasses)
  390.        new-getter-fns))
  391.      (slots (vector-ref combined-slots 0))
  392.      (class-data-size (vector-ref combined-slots 1))
  393.      (instance-data-size (vector-ref combined-slots 2)))
  394.     (set-class.slots! the-class slots)
  395.     (set-class.class-data!
  396.      the-class
  397.      ;; Design note: we flatten out the slot list here to make
  398.      ;; instance creation fast at the expense of speed of class
  399.      ;; redefinition and space.
  400.      (let ((result
  401.         (make-vector class-data-size *the-uninitialized-slot-value*)))
  402.        (vector-iterate slots
  403.                (lambda (i slot)
  404.              i
  405.              (initialize-slot! slot '() result '(EACH-SUBCLASS))))
  406.        result))
  407.     (set-class.instance-data-size! the-class instance-data-size)
  408.     (for-each
  409.      (lambda (parent-class)
  410.        (add-to-population! (class.subclasses parent-class) the-class))
  411.      superclasses)
  412.     (if (not top?) (recompute-class-specificities!))
  413.     the-class))
  414.  
  415. (set! Subclass?
  416.   (lambda (class1 class2)
  417.     ; Is class1 a subclass of class2?
  418.     (or (Id? class1 class2)
  419.     (let loop ((classes-left (class.superclasses class1)))
  420.       (cond ((null? classes-left) #F)
  421.         ((Id? class2 (car classes-left)) #T)
  422.         (else (loop (append (class.superclasses (car classes-left))
  423.                     (cdr classes-left)))))))))
  424.  
  425. (set! Add-Slot
  426.   (lambda (owner . keyword-list)
  427.     ;; Keywords allowed are: getter, setter, type, init-value,
  428.     ;; init-function, init-keyword, required-init-keyword, debug-name, and
  429.     ;; allocation. See page 52.
  430.     (dylan::keyword-validate
  431.      #F keyword-list
  432.      '(getter: setter: type: init-value: init-function: init-keyword:
  433.            required-init-keyword: allocation: debug-name:))
  434.     (let* ((getter (dylan::find-keyword
  435.             keyword-list 'getter:
  436.             (lambda ()
  437.               (dylan-call dylan:error "no getter defined"))))
  438.        (setter (dylan::find-keyword keyword-list 'setter:
  439.                        dylan::false-fn))
  440.        (type (dylan::find-keyword keyword-list 'type:
  441.                      (lambda () <Object>)))
  442.        (have-init-value? #T)
  443.        (init-value (dylan::find-keyword
  444.             keyword-list 'init-value:
  445.             (lambda ()
  446.               (set! have-init-value? #F)
  447.               'no-value)))
  448.        (init-function (dylan::find-keyword
  449.                keyword-list 'init-function:
  450.                dylan::false-fn))
  451.        (init-keyword (dylan::find-keyword
  452.               keyword-list 'init-keyword:
  453.               dylan::false-fn))
  454.        (allocation (dylan::find-keyword
  455.             keyword-list 'allocation:
  456.             (lambda () 'instance)))
  457.        (debug-name (dylan::find-keyword
  458.             keyword-list 'debug-name:
  459.             (lambda () '*the-unnamed-slot*)))
  460.        (required-init-keyword (dylan::find-keyword
  461.                    keyword-list 'required-init-keyword:
  462.                    (lambda () #F))))
  463.       (dylan::add-slot owner
  464.                type allocation setter getter debug-name init-value
  465.                have-init-value? init-function init-keyword
  466.                required-init-keyword))))
  467.  
  468. (define (same-slot-getter-in-slot-vector->slot getter slots)
  469.   (let loop ((slots (vector->list slots)))
  470.     (cond ((null? slots) #F)
  471.       ((Id? (slot.getter (car slots)) getter) (car slots))
  472.       (else (loop (cdr slots))))))
  473.  
  474. (define (conflict-test owner new-slot)
  475.   (define (stricter-than-all? type type-list)
  476.     ; type-list may contain #F entries!
  477.     (let loop ((rest-list type-list))
  478.       (cond ((null? rest-list) #T)
  479.         ((or (not (car rest-list)) (subclass? type (car rest-list)))
  480.          (loop (cdr rest-list)))
  481.         (else #F))))
  482.   (if (not (stricter-than-all?
  483.         (slot.type new-slot)
  484.         (map (lambda (class)
  485.            (cond ((same-slot-getter-in-slot-vector->slot
  486.                (slot.getter new-slot)
  487.                (class.slots class)) => slot.type)
  488.              (else #F)))
  489.          (class.superclasses
  490.           (if (class? owner)
  491.               owner
  492.               (instance.class (singleton.object owner)))))))
  493.       (dylan-call
  494.        dylan:error
  495.        "conflict-test -- new slot type not a subclass of inherited type"
  496.        'owner owner
  497.        'new-slot new-slot
  498.        'new-slot-type (slot.type new-slot))))
  499.  
  500. (define (remove-this-slot-only! owner slot-vector slot)
  501.   (vector-iterate slot-vector
  502.     (lambda (index entry)
  503.       (if (Id? slot entry)
  504.       (let ((allocation (slot.allocation slot))
  505.         (data-location (slot.data-location slot)))
  506.         (vector-set! slot-vector index #F)
  507.         (if (class? owner)
  508.         (case allocation
  509.           ((CLASS)
  510.            (if (eq? (car data-location) owner)
  511.                (vector-set! (class.class-data owner)
  512.                     (cdr data-location)
  513.                     '<<EMPTY-SLOT-VALUE>>)))
  514.           ((EACH-SUBCLASS)
  515.            (vector-set! (class.class-data owner)
  516.                 data-location
  517.                 '<<EMPTY-SLOT-VALUE>>))
  518.           ((INSTANCE)
  519.            (map-over-population
  520.             (class.instances owner)
  521.             (lambda (ins)
  522.               (vector-set! (instance.data ins)
  523.                    data-location
  524.                    '<<EMPTY-SLOT-VALUE>>)))))
  525.         ;; Not a class, must be a singleton
  526.         (if (eq? allocation 'instance)
  527.             (vector-set! owner
  528.                  data-location
  529.                  '<<EMPTY-SLOT-VALUE>>))))))))
  530.  
  531. (define (add-a-slot owner new-slot accessor updater fixit-fn)
  532.   ;; Adds new-slot (a slot descriptor) to the owner, using accessor to
  533.   ;; find the current list of slot descriptors and updater to store
  534.   ;; the modified list back if needed.  Fixit-Fn is then called with
  535.   ;; the slot descriptor and owner to update the instances as needed.
  536.   (let* ((current-descriptors (accessor owner))
  537.      (getter (slot.getter new-slot))
  538.      (old-slot (same-slot-getter-in-slot-vector->slot
  539.             getter current-descriptors)))
  540.     (if old-slot
  541.     (begin                ; Redefining existing slot
  542.       (if (slot.inherited? old-slot)
  543.           (conflict-test owner new-slot))
  544.       (remove-this-slot-only! owner current-descriptors old-slot)
  545.       (set! current-descriptors (accessor owner))))
  546.     (let ((offset (find-empty-slot current-descriptors)))
  547.       (if offset
  548.       (vector-set! current-descriptors offset new-slot)
  549.       (updater owner (grow-vector current-descriptors new-slot)))
  550.       (fixit-fn owner new-slot))))
  551.  
  552. (set! map-over-all-subclasses!
  553.   (lambda (predicate fn classes)
  554.     ;; Predicate is #T if you want to continue to children of this class
  555.     ;; FN receives two arguments: a class and (predicate class)
  556.     ;; Classes appear only once, even if multiple inheritance
  557.     ;; makes a non-tree
  558.     (let loop ((subclasses (population->list classes))
  559.            (already-seen '()))
  560.       (if (null? subclasses)
  561.       'done
  562.       (let* ((this-subclass (car subclasses))
  563.          (test (predicate this-subclass)))
  564.         (if (not (memq this-subclass already-seen))
  565.         (fn this-subclass test))
  566.         (loop (if test
  567.               (append (cdr subclasses)
  568.                   (population->list
  569.                    (class.subclasses (car subclasses))))
  570.               (cdr subclasses))
  571.           (cons this-subclass already-seen)))))))
  572.  
  573. (set! map-over-all-superclasses!
  574.   (lambda (class fn)
  575.     (let loop ((superclasses (class.superclasses class))
  576.            (already-seen (list class)))
  577.       (if (null? superclasses)
  578.       (reverse already-seen)
  579.       (let ((this-class (car superclasses)))
  580.         (let ((new-ones
  581.            (set-difference (class.superclasses this-class)
  582.                    already-seen
  583.                    memq)))
  584.           (fn this-class)
  585.           (loop (append (cdr superclasses) new-ones)
  586.             (cons this-class already-seen))))))))
  587.  
  588. (define (add-slot-to-class! class new-slot)
  589.   (case (slot.allocation new-slot)
  590.     ((INSTANCE)
  591.      (map-over-population!
  592.       (class.instances class)
  593.       (lambda (instance)
  594.     (set-instance.data! instance
  595.                 (grow-vector (instance.data instance)
  596.                      (get-initial-slot-value new-slot)))))
  597.      (add-method (slot.getter new-slot)
  598.          (make-instance-getter class
  599.                        (class.instance-data-size class)
  600.                        (slot.debug-name new-slot)))
  601.      (if (slot.setter new-slot)
  602.      (add-method (slot.setter new-slot)
  603.              (make-instance-setter class
  604.                        (class.instance-data-size class)
  605.                        (slot.type new-slot))))
  606.      (set-class.instance-data-size! class (+ (class.instance-data-size class)
  607.                          1)))
  608.     ((EACH-SUBCLASS)
  609.      (add-method (slot.getter new-slot)
  610.          (make-each-subclass-getter
  611.           class
  612.           (vector-length (class.class-data class))
  613.           (slot.debug-name new-slot)))
  614.      (if (slot.setter new-slot)
  615.      (add-method (slot.setter new-slot)
  616.              (make-each-subclass-setter
  617.               class
  618.               (vector-length (class.class-data class))
  619.               (slot.type new-slot))))
  620.      (set-class.class-data! class
  621.                 (grow-vector (class.class-data class)
  622.                      (get-initial-slot-value new-slot))))
  623.     ((CLASS)
  624.      (let ((data-location (slot.data-location new-slot)))
  625.        (if (eq? class (car data-location))
  626.        (let ((offset (cdr data-location)))
  627.          (set-class.class-data! class
  628.                     (grow-vector
  629.                      (class.class-data class)
  630.                      (get-initial-slot-value new-slot)))
  631.          (add-method (slot.getter new-slot)
  632.              (make-class-getter class
  633.                         offset
  634.                         (slot.debug-name new-slot)))
  635.          (if (slot.setter new-slot)
  636.          (add-method (slot.setter new-slot)
  637.              (make-class-setter class offset
  638.                         (slot.type new-slot))))))))
  639.     ((VIRTUAL CONSTANT) #T)))
  640.  
  641. (define (add-slot-to-singleton! singleton new-slot)
  642.   (if (eq? (slot.allocation new-slot) 'INSTANCE)
  643.       (begin
  644.     (set-singleton.extra-slot-values!
  645.      singleton
  646.      (grow-vector (singleton.extra-slot-values singleton)
  647.               (get-initial-slot-value new-slot)))
  648.     (add-method (slot.getter new-slot)
  649.             (make-singleton-getter singleton
  650.                        (slot.data-location new-slot)
  651.                        (slot.debug-name new-slot)))
  652.     (if (slot.setter new-slot)
  653.         (add-method (slot.setter new-slot)
  654.             (make-singleton-setter
  655.              singleton (slot.data-location new-slot)
  656.              (slot.type new-slot)))))))
  657.  
  658. (set! dylan::add-slot
  659.   (lambda (owner type allocation setter getter debug-name init-value
  660.        has-init-value? init-function init-keyword required-init-keyword)
  661.     (define (figure-data-location current-class allocation)
  662.       (if (class? current-class)
  663.       (case allocation        ; CLASS
  664.         ((VIRTUAL) #F)
  665.         ((CONSTANT) init-value)
  666.         ((INSTANCE) (class.instance-data-size current-class))
  667.         ((EACH-SUBCLASS) (vector-length (class.class-data current-class)))
  668.         ((CLASS) (cons owner (vector-length (class.class-data owner)))))
  669.       (case allocation        ; SINGLETON
  670.         ((VIRTUAL) #F)
  671.         ((CONSTANT) init-value)
  672.         ((INSTANCE)
  673.          (vector-length (singleton.extra-slot-values current-class)))
  674.         (else
  675.          (dylan-call dylan:error
  676.              "dylan::add-slot -- bad allocation for singleton"
  677.              current-class debug-name allocation)))))
  678.     (cond ((singleton? owner)
  679.        (if (not (memq allocation '(instance constant virtual)))
  680.            (dylan-call dylan:error
  681.                "dylan::add-slot -- bad singleton allocation"
  682.                allocation))
  683.        (if init-keyword
  684.            (dylan-call dylan:error
  685.                "dylan::add-slot -- singleton with init-keyword"
  686.                init-keyword)))
  687.       ((and (class? owner) (class.read-only? owner))
  688.        (dylan-call dylan:error "add-slot -- class is read-only" owner))
  689.       ((not (class? owner))
  690.        (dylan-call dylan:error
  691.                "dylan::add-slot -- owner not a singleton or class"
  692.                owner)))
  693.     (if (and required-init-keyword
  694.          (or init-keyword has-init-value? init-function))
  695.     (dylan-call dylan:error
  696.             "dylan::add-slot -- incompatible slot initialization"
  697.             'required-init-keyword required-init-keyword
  698.             'init-keyword init-keyword
  699.             'init-value init-value
  700.             'init-function init-function))
  701.     (if (and has-init-value? init-function)
  702.     (dylan-call dylan:error
  703.             "dylan::add-slot -- both initial value and function"
  704.             'init-value init-value
  705.             'init-function init-function))
  706.     (if (not (memq allocation '(instance class each-subclass
  707.                      constant virtual)))
  708.     (dylan-call dylan:error
  709.             "dylan::add-slot -- bad allocation type" allocation))
  710.     (if (and (memq allocation '(class each-subclass))
  711.          (or init-function required-init-keyword init-keyword))
  712.     (dylan-call
  713.      dylan:error
  714.      "dylan::add-slot -- bad combination of allocation and initialization"
  715.      allocation init-function required-init-keyword init-keyword))
  716.     (let ((new-slot (make-slot
  717.              debug-name getter setter type init-value
  718.              has-init-value? init-function init-keyword
  719.              required-init-keyword allocation #F
  720.              (figure-data-location owner allocation))))
  721.       (if (class? owner)
  722.       (begin
  723.         (add-a-slot owner new-slot
  724.             class.slots set-class.slots!
  725.             add-slot-to-class!)
  726.         (map-over-all-subclasses!
  727.          (lambda (class)
  728.            ;; Stop showering down if we hit a class that already has a
  729.            ;; generic function for this slot.
  730.            (not (memq getter (map slot.getter
  731.                       (vector->list (class.slots class))))))
  732.          (lambda (class test)
  733.            (if test
  734.            (add-a-slot
  735.             class
  736.             (copy-slot new-slot #T
  737.                    (figure-data-location class allocation))
  738.             class.slots set-class.slots! add-slot-to-class!)
  739.            (conflict-test class (copy-slot new-slot #T 0))))
  740.          (class.subclasses owner)))
  741.       (add-a-slot owner new-slot    ; SINGLETON
  742.               singleton.extra-slot-descriptors
  743.               set-singleton.extra-slot-descriptors!
  744.               add-slot-to-singleton!))
  745.       new-slot)))
  746.  
  747. (define (make-getter-param-list class)
  748.   (make-param-list `((OBJ ,class)) #F #F #F))
  749.  
  750. (define (make-setter-param-list class)
  751.   (make-param-list `((OBJ ,class) (VALUE ,<object>)) #F #F #F))
  752.  
  753. (define (object-ref data offset object name)
  754.   (let ((value (vector-ref data offset)))
  755.     (if (eq? value *the-uninitialized-slot-value*)
  756.     (dylan-call dylan:error "uninitialized slot accessed" object name)
  757.     value)))
  758.  
  759. (define (make-class-getter class offset name)
  760.   (dylan::function->method
  761.    (make-getter-param-list class)
  762.    (lambda (obj) obj (object-ref (class.class-data class) offset class name))))
  763.  
  764. (define (make-each-subclass-getter class offset name)
  765.   (dylan::function->method
  766.    (make-getter-param-list class)
  767.    (lambda (obj)
  768.      (let ((class (instance.class obj)))
  769.        (object-ref (class.class-data class) offset class name)))))
  770.  
  771. (define (make-instance-getter class offset name)
  772.   (dylan::function->method
  773.    (make-getter-param-list class)
  774.    (lambda (obj)
  775.      (object-ref (instance.data obj) offset obj name))))
  776.  
  777. (define (make-singleton-getter class singleton offset name)
  778.   (dylan::function->method
  779.    (make-getter-param-list class)
  780.    (lambda (obj)
  781.      obj                ; Ignored
  782.      (object-ref (singleton.extra-slot-values singleton) offset
  783.          singleton name))))
  784.  
  785. (define (make-class-setter class offset type)
  786.   (dylan::function->method
  787.    (make-setter-param-list class)
  788.    (if (eq? type <object>)
  789.        (lambda (obj value)
  790.      obj                ; Ignored
  791.      (vector-set! (class.class-data class) offset value)
  792.      value)
  793.        (lambda (obj value)
  794.      obj
  795.      (dylan-call dylan:check-type value type)
  796.      (vector-set! (class.class-data class) offset value)
  797.      value))))
  798.  
  799. (define (make-each-subclass-setter class offset type)
  800.   (dylan::function->method
  801.    (make-setter-param-list class)
  802.    (if (eq? type <object>)
  803.        (lambda (obj value)
  804.      (vector-set! (class.class-data (instance.class obj)) offset value)
  805.      value)
  806.        (lambda (obj value)
  807.      (dylan-call dylan:check-type value type)
  808.      (vector-set! (class.class-data (instance.class obj)) offset value)
  809.      value))))
  810.  
  811. (define (make-instance-setter class offset type)
  812.   (dylan::function->method
  813.    (make-setter-param-list class)
  814.    (if (eq? type <object>)
  815.        (lambda (obj value)
  816.      (vector-set! (instance.data obj) offset value)
  817.      value)
  818.        (lambda (obj value)
  819.      (dylan-call dylan:check-type value type)
  820.      (vector-set! (instance.data obj) offset value)
  821.      value))))
  822.  
  823. (define (make-singleton-setter class singleton offset type)
  824.   (dylan::function->method
  825.    (make-setter-param-list class)
  826.    (if (eq? type <object>)
  827.        (lambda (obj value)
  828.      obj                ; Ignored
  829.      (vector-set! (singleton.extra-slot-values singleton) offset value)
  830.      value)
  831.        (lambda (obj value)
  832.      obj
  833.      (dylan-call dylan:check-type value type)
  834.      (vector-set! (singleton.extra-slot-values singleton) offset value)
  835.      value))))
  836.  
  837. (define (make-constant-getter class constant)
  838.   (dylan::function->method
  839.    (make-getter-param-list class)
  840.    (lambda (obj)
  841.      obj                ;Ignored
  842.      constant)))
  843.  
  844. (define (dylan::make-singleton object)
  845.   (if (instance? object)
  846.       (or (instance.singleton object)
  847.       (let ((singleton (make-singleton object '#() '#())))
  848.         (set-instance.singleton! object singleton)
  849.         singleton))
  850.       (make-singleton object '#() '#())))
  851.